import base64
import os
import threading

import cv2
import redis

from loguru import logger

from common import wrapper, utils, model


def get_redis_client():
    host = os.getenv('BIND_IP', '127.0.0.1')
    port = int(os.getenv('REDIS_PORT', 6379))
    logger.info('redis url={}:{}'.format(host, port))
    rc = redis.Redis(host=host, port=port, db=0)
    return rc


class OpenVideo(threading.Thread):
    Instance = None

    def __new__(cls, *args, **kwargs):
        if cls.Instance and not kwargs.get('reconstruction'):
            return cls.Instance
        cls.Instance = object.__new__(cls)
        return cls.Instance

    def __init__(self):
        super().__init__()
        self.video_path = None
        self.rc = get_redis_client()
        self.video: cv2.VideoCapture = None
        self.video_attribute: model.VideoAttribute = None

    @wrapper.ignore_exception
    def open_video(self, path):
        if not os.path.isabs(path):
            path = os.path.join(os.getenv('INPUT_DIR'), path)
        if not os.path.isabs(path):
            path = os.path.abspath(path)
        if not os.path.isfile(path):
            raise Exception('open {} failed, not exist'.format(path))
        err_msg = "can't open {}".format(path)
        video_capture = cv2.VideoCapture(path)
        if video_capture and video_capture.isOpened():
            ret, frame = video_capture.read()
            if ret:
                logger.info('成功打开视频 {}'.format(path))
                count = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
                height = video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
                width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)
                fps = video_capture.get(cv2.CAP_PROP_FPS)
            else:
                raise Exception(err_msg)
        else:
            raise Exception(err_msg)
        attribute = {'count': count, 'path': path,
                     'height': height, 'width': width, 'fps': fps}
        logger.info('open {} success'.format(path))
        self.video_path, self.video, self.video_attribute = path, video_capture, model.VideoAttribute(**attribute)
        self.rc.publish('view_control', str(self.video_attribute.count))

    @wrapper.ignore_exception
    def get_a_capture(self, progress: int):
        if not 0 <= progress <= 100:
            raise Exception('progress={} not in [0,100]')
        count = int(self.video_attribute.count * progress / 100)
        self.video.set(cv2.CAP_PROP_POS_FRAMES, count)
        ret, frame = self.video.read()
        if ret:
            self.publish_image(frame)
            # frame = cv2.resize(src=frame, dsize=(800, 600))
            # logger.info('get progress={} video capture'.format(progress))
            # show = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            # return transfer.cv2bytes(show)

    def publish_image(self, frame):
        image = cv2.imencode('.jpg', frame)[1]
        image_code = str(base64.b64encode(image))[2:-1]
        base64_image = 'data:image/jpeg;base64,' + image_code
        self.rc.publish('video_capture', base64_image)
        # self.rc.set('capture', base64_image)

    def run(self):
        rc = get_redis_client()
        ps = rc.pubsub()
        ps.subscribe('control')
        for item in ps.listen():
            if item['type'] == 'message':
                value = bytes.decode(item['data'])
                logger.info("receive control value='{}'".format(value))
                if value.startswith('path='):
                    path = value[5:]
                    path = utils.unescape(path)
                    self.open_video(path)
                    self.rc.set('video_path', self.video_path)
                elif value.startswith('bar='):
                    self.get_a_capture(int(value[4:]))

    """
    def select_subttle_area_complete(self, value):
        label_w, label_h = self.show_video_label.width(), self.show_video_label.height()
        rect_x0, rect_y0, rect_x1, rect_y1 = value
        x_b, y_b = SoftData.Video.width / label_w, SoftData.Video.height / label_h
        real_x0, real_x1 = int(rect_x0 * x_b), int(rect_x1 * x_b)
        real_y0, real_y1 = int(rect_y0 * y_b), int(rect_y1 * y_b)
        msg = '在真实视频分辨率下矩形范围为 A=({},{}) B=({},{})'.format(real_x0, real_y0, real_x1, real_y1)
        self.add_log(msg)
        SoftData.Video.rect = real_x0, real_y0, real_x1, real_y1
        self.subtitle_area_lineedit.setText(msg)

    def set_subtitle_area(self):
        self.show_video_label.enable_paint_rect_flag = True
        self.subtitle_area_lineedit.setText('开始')

    def start_extract(self):
        self.extract_video_sound()

    def __deal_with_process_output_string(self, input_str):
        str1 = bytearray(input_str)
        str1 = str1.decode('gbk').strip()
        if str1:
            self.add_log(str1)
            progress = get_extract_voice_progress(str1)
            if progress:
                progress = progress / 100 * 10
                self.update_progress_bar(progress)

    def test_connect_api(self):
        self.add_log('开始测试api接口是否连通')
        try:
            value = self.api_interface.detect_recognition_model()
            if isinstance(value, dict) and value.get('result') == 'load model success':
                msg = '文字识别API接口已连通:{}'.format(self.api_interface.base_url)
                self.add_log(msg)
                self.connect_api_lineedit.setText(msg)
        except Exception as e:
            msg = '无法连接文字识别API接口，检查容器状态后重试'
            self.add_log('{}, err={}'.format(msg, e))
            self.connect_api_lineedit.setText(msg)

    def update_progress_bar(self, progress):
        self.extract_progress.setValue(progress)

    def add_log(self, str1):
        self.background_print_textedit.append(str1)

    def open_video(self):
        video_path = self.video_path_lineedit.text()
        self.video_capture = cv2.VideoCapture(video_path)
        SoftData.Video.opened_cv = self.video_capture
        if self.video_capture and self.video_capture.isOpened():
            ret, frame = self.video_capture.read()
            if ret:
                self.add_log('成功打开视频 {}'.format(video_path))
                SoftData.Video.count = int(self.video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
                self.video_slider.setMaximum(SoftData.Video.count)
                SoftData.Video.height = self.video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
                SoftData.Video.width = self.video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)
                SoftData.Video.fps = self.video_capture.get(cv2.CAP_PROP_FPS)
                # self.load_picture.
                self.show_video_label_thread.start()
                self.show_video_label_thread.value = 0

    def show_video_by_count(self, value):
        if not self.show_video_label_thread.busy:
            self.show_video_label_thread.value = [value]
        else:
            time.sleep(0.1)

    def open_dialog_select_video_file(self):
        video_file_path = QFileDialog.getOpenFileName(self, '选择文件')[0]
        SoftData.Path.video = video_file_path
        video_filename = os.path.split(video_file_path)[1]
        just_name = ''.join(video_filename.split('.')[:-1])
        SoftData.Path.sound = os.path.abspath(os.path.join(current_dir, 'temp', '{}.mp3'.format(just_name)))
        self.add_log('设置{}提取出的声音文件为 {}'.format(video_filename, SoftData.Path.sound))
        if video_file_path:
            self.video_path_lineedit.setText(video_file_path)
            self.open_video()
        else:
            self.video_path_lineedit.setText(SoftData.Step.step1)

    def update_stderr(self):
        str1 = self.process.readAllStandardError()
        self.__deal_with_process_output_string(str1)

    def update_stdout(self):
        str1 = self.process.readAllStandardOutput()
        self.__deal_with_process_output_string(str1)

    def add_string_text(self, str1):
        self.add_log(str1)

    def process_finished(self, exitCode, exitStatus):
        if exitCode != 0:
            self.log_signal.emit('Abnormal End, exitCode={}, existStatus={}'.format(exitCode, exitStatus))
            QMessageBox.critical(self, 'command exception', 'process existed abnormally',
                                 QMessageBox.Yes, QMessageBox.Yes)

        else:
            self.add_log('Normal End, exitCode={}, existStatus={}'.format(exitCode, exitStatus))
            self.extract_thread.start()

    def extract_video_sound(self):
        if os.path.isfile(SoftData.Path.sound):
            self.add_log('已经提取了声音文件 {}'.format(SoftData.Path.sound))
            self.update_progress_bar(10)
            self.extract_thread.start()
        else:
            cmd = "ffmpeg -i {} {} -y".format(SoftData.Path.video, SoftData.Path.sound)
            self.add_log(cmd)
            cmd_list = cmd.split(' ')
            self.process.start(cmd_list[0], cmd_list[1:])
            
    """
